package cn.com.surker.baidu;

import cn.com.surker.baidu.ai.Base64Util;
import cn.com.surker.baidu.ai.FileUtil;
import cn.com.surker.baidu.ai.HttpUtil;
import cn.com.surker.baidu.model.OCRBankReturnModel;
import cn.com.surker.baidu.model.OCRMaterialModel;
import cn.com.surker.common.HttpRequestHelper;
import cn.com.surker.redis.RedisUtils;
import cn.com.surker.spring.SpringContextHolder;
import cn.com.surker.util.DateUtil;
import cn.com.surker.util.MathUtils;
import cn.com.surker.util.StringUtils;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.time.DateFormatUtils;

import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.*;


/**
 * @Author lucky
 * @create 2023年04月17 10:44
 * @desc 百度图像识别API
 */
@Slf4j
public class OCRAipApi {
//
    /***API Key**/
//    public static String ocrApiKey = "LgaLpogQM5hM5CfiEuEDa49Q";
//    /***Secret Key**/
//    public static String ocrSecretKey = "0fw5nbmvOhGkzdWHihjR5L2KZxAEwUgF";
//    /***API ID**/
//    public static String ocrApiID = "32375376";

    /***API Key**/
    public static final String ocrApiKey = "hywB6Y4B4MaVIIuE3n2PwY2C";
    /***Secret Key**/
    public static final String ocrSecretKey = "BEGr1NTWjmgLISKm4uOXNelYYref95fp";
    /***API ID**/
    public static final String ocrApiID = "33861692";

//    /***API Key**/
//    public static String outOcrApiKey = "tRfcy5SHZC4cskhdo2o8234r";
//    /***Secret Key**/
//    public static String outOcrSecretKey = "Yf6yonluXkQdHdaGuZv7gPUHMh0djek2";
//    public static String outOcrApiID = "33682997";

    public static String twoMaterialClassId = "1";//地材分类器
    public static String oneMaterialClassId = "2";//粉料分类器

	//	财务分类器
	public static String BANK_PAYMENT_CLASS_ID = "10";

    /**连接类型**/
    public static final String grantType = "client_credentials";

    public static final String ocrTokenKey = "ocr_aip_key";
    public static final String outOcrTokenKey = "out_ocr_aip_key";
    public static final Long sessionExpired = 108000L;
    public static final Map<Integer, Integer> originMap = new HashMap<>();
    public static final Map<Integer, String> errorMap = new HashMap<>();
    static {
        originMap.put(2, 6);//雅博
        originMap.put(6, 3);//驰旭
        originMap.put(9, 6);//赛华
        originMap.put(8, 5);//鑫悦
        originMap.put(4, 5);//圣同
        originMap.put(17, 6);//鑫悦二站
        originMap.put(12, 6);//东阳
        originMap.put(1, 8);//博久
        originMap.put(14, 8);//创领
        originMap.put(15, 7);//真源
        originMap.put(21, 9);//真源
        originMap.put(22, 12);//地盾
        originMap.put(23, 6);//雅博新站
        originMap.put(10, 13);//中冠
        originMap.put(24, 3);//驰旭
        originMap.put(25, 6);//博久
        originMap.put(11, 14);//正佳
        originMap.put(18, 14);//午阳
        originMap.put(28, 15);//午阳
        originMap.put(26, 8);//午阳
        originMap.put(30, 5);//鑫悦

        errorMap.put(1, "未知错误，请再次请求");
        errorMap.put(2, "服务暂不可用，请再次请求");
        errorMap.put(3, "调用的API不存在，请检查后重新尝试");
        errorMap.put(4, "集群超限额");
        errorMap.put(6, "无接口调用权限");
        errorMap.put(100, "无效的access_token参数");
        errorMap.put(110, "access_token无效");
        errorMap.put(111, "access token过期");
        errorMap.put(216100, "请求中包含非法参数");
        errorMap.put(216102, "请求了不支持的服务，请检查调用的url");
        errorMap.put(216200, "图片为空");
        errorMap.put(216201, "上传的图片格式错误，现阶段我们支持的图片格式为：PNG、JPG、JPEG、BMP");
        errorMap.put(216202, "上传的图片大小错误，现阶段我们支持的图片大小为：base64编码后小于4M，分辨率不高于4096x4096，请重新上传图片");
        errorMap.put(216630, "识别错误，请再次请求");
        errorMap.put(272000, "未进行分类，未能匹配模板");
        errorMap.put(272001, "未能成功分类，请检查识别图片所属类别分类器中是否存在");
        errorMap.put(272002, "分类成功，但未能匹配模板");
        errorMap.put(272003, "未能成功检测到票据，请检查识别图片是否为票据粘贴单");
        errorMap.put(272004, "分类器不存在");
        errorMap.put(272005, "关键词分类失败");
        errorMap.put(282000, "服务器内部错误，可能是图片尺寸过大文字太多识别超时");
        errorMap.put(282004, "您指定的模板暂未发布，请先发布该模板，再调用");
        errorMap.put(282102, "未检测到图片中识别目标，请确保图片中包含对应卡证票据");
        errorMap.put(282103, "图片目标识别错误，请确保图片中包含对应卡证票据");
    }

    public static void main(String[] args){
//        AipOcr client = getAipOcr();
//        System.out.println(getImageContent(client, "https://cloud.chixugroup.com/file/preview/22652"));
//        System.out.println(getImageContent(client, "https://cloud.chixugroup.com/file/preview/22655"));
//        System.out.println(getImageContent(client, "https://cloud.chixugroup.com/file/preview/22656"));
//
//
//        System.out.println(getImageContent(client, "https://cloud.chixugroup.com/file/preview/22654"));
//        System.out.println(getImageContent(client, "https://cloud.chixugroup.com/file/preview/22653"));
//        getAccessToken("", "");
//        String token = "24.543808c01eb6c9066b236b67ff88a906.2592000.1684313074.282335-32375376";
////        OCRMaterialModel model = getImageContent("C:\\Users\\slaye\\Desktop\\img\\6dad9530-4612-4738-8866-e373a17f2f69.jpg",
////                oneMaterialClassId, token);
//        String json = getImageContent("https://cloud.chixugroup.com/file/preview/22656",
//                oneMaterialClassId, token);
//        OCRMaterialModel model = convertModel(json);
    }

    public static String docRepair(String imgParam, String token) {
        // 请求url
        String url = "https://aip.baidubce.com/rest/2.0/image-process/v1/doc_repair";
        try {
            if (StringUtils.isNull(token))
                token = getAccessToken(ocrApiKey, ocrSecretKey);
            String param = "image=" + imgParam;

            String result = HttpUtil.post(url, token, param);
            if (!StringUtils.isNull(result)) {
                JSONObject json = JSONObject.parseObject(result);
                if (!StringUtils.isNull(json.getString("result"))) {
                    return json.getString("result");
                }
            }
            return "";
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

    /**
     * 去除底纹图片识别文字信息
     * @param imgData 图片二进制
     * @param classId 模板ID
     * @param token 调用token
     * @return
     */
    public static String getOutImageContent(byte[] imgData, String classId, String token) {
        // iocr识别apiUrl
        String recogniseUrl = "https://aip.baidubce.com/rest/2.0/solution/v1/iocr/recognise";
        try {
            log.info("-----去底纹识别-----");
            if (StringUtils.isNull(token))
                token = getAccessToken(ocrApiKey, ocrSecretKey);
            String imgStr = Base64Util.encode(imgData);
            String imgParam = URLEncoder.encode(imgStr, "UTF-8");
            String param = docRepair(imgParam, token);
            if (!StringUtils.isNull(param)) {
                imgParam = URLEncoder.encode(param, "UTF-8");
            }

            // 请求分类器参数
            String classifierParams = "classifierId=" + classId + "&image=" + imgParam;

            if (StringUtils.isNull(token))
                token = getAccessToken(ocrApiKey, ocrSecretKey);
            // 请求模板识别
//            String result = HttpUtil.post(recogniseUrl, token, recogniseParams);
            // 请求分类器识别
            String result = HttpUtil.post(recogniseUrl, token, classifierParams);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

    /**
     * 根据图片识别文字信息
     * @param imgData 图片二进制
     * @param classId 模板ID
     * @param token 调用token
     * @return
     */
    public static String getImageContent(byte[] imgData, String classId, String token) {
        // iocr识别apiUrl
        String recogniseUrl = "https://aip.baidubce.com/rest/2.0/solution/v1/iocr/recognise";
        try {
            if (StringUtils.isNull(token))
                token = getAccessToken(ocrApiKey, ocrSecretKey);
            String imgStr = Base64Util.encode(imgData);
            String imgParam = URLEncoder.encode(imgStr, "UTF-8");
            // 请求分类器参数
            String classifierParams = "classifierId=" + classId + "&image=" + imgParam;

            if (StringUtils.isNull(token))
                token = getAccessToken(ocrApiKey, ocrSecretKey);
            // 请求模板识别
//            String result = HttpUtil.post(recogniseUrl, token, recogniseParams);
            // 请求分类器识别
            String result = HttpUtil.post(recogniseUrl, token, classifierParams);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

    /**
     *
     * @param url 图片本地路径
     * @param classId 模板ID
     * @param token
     * @return
     */
    public static String getImageContent(String url, String classId, String token) {
        // iocr识别apiUrl
        String recogniseUrl = "https://aip.baidubce.com/rest/2.0/solution/v1/iocr/recognise";
        try {
            if (StringUtils.isNull(token))
                token = getAccessToken(ocrApiKey, ocrSecretKey);

            byte[] imgData = FileUtil.readFileByBytes(url);
            String imgStr = Base64Util.encode(imgData);
            // 请求模板参数
//            String recogniseParams = "templateSign=2d9dbbf1fdcfaf1c354d3153af8697f1&image=" + URLEncoder.encode(imgStr, "UTF-8");
            // 请求分类器参数
            String classifierParams = "classifierId=" + classId + "&image=" + URLEncoder.encode(imgStr, "UTF-8");

            if (StringUtils.isNull(token))
                token = getAccessToken(ocrApiKey, ocrSecretKey);
            // 请求模板识别
//            String result = HttpUtil.post(recogniseUrl, token, recogniseParams);
            // 请求分类器识别
             String result = HttpUtil.post(recogniseUrl, token, classifierParams);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

    /**
     * 将json数据转换成实体
     * @param result
     * @return
     */
    public static OCRMaterialModel convertModel(String result) {
        JSONObject json = JSONObject.parseObject(result);
        log.info("图片识别JSON：" + result);
        if (!StringUtils.isNull(json.getInteger("error_code")) && json.getInteger("error_code") == 0) {
            JSONObject jsonData = json.getJSONObject("data");//识别结果集
            if (jsonData != null) {
                JSONArray retArray = jsonData.getJSONArray("ret");
                if (retArray != null) {
                    OCRMaterialModel model = new OCRMaterialModel();
                    for (int i = 0; i < retArray.size(); i++) {
                        JSONObject retJson = retArray.getJSONObject(i);
                        //名称
                        String wordName = StringUtils.convertString(retJson.getString("word_name"));
                        //识别值
                        String word = StringUtils.convertString(retJson.getString("word"));
                        if (wordName.equals("材料")) {
                            model.setMaterialKey(wordName);
                            model.setMaterialValue(word);
                        } else if (wordName.equals("车牌")) {
                            model.setCarNoKey(wordName);
                            model.setCarNoValue(word);
                        } else if (wordName.equals("毛重")) {
                            model.setGrossKey(wordName);
                            model.setGrossValue(word);
                        } else if (wordName.equals("净重")) {
                            model.setNetWeightKey(wordName);
                            model.setNetWeightValue(word);
                        } else if (wordName.equals("皮重")) {
                            model.setTareKey(wordName);
                            model.setTareValue(word);
                        }
                    }
                    return model;
                }
            }
        } else if (!StringUtils.isNull(json.getInteger("error_code"))) {
            Integer errorCode = json.getInteger("error_code");
            String errorMessage = errorMap.get(errorCode);
            if (!StringUtils.isNull(errorMessage)) {
                OCRMaterialModel model = new OCRMaterialModel();
                model.setErrorMessage(errorMessage);
            }
        }
        return null;
    }

    /**
     * 获取通用识别去底纹token
     * @param apiKey
     * @param secretKey
     * @return
     */
    public static String getOutAccessToken(String apiKey, String secretKey) {
        if (StringUtils.isNull(apiKey))
            apiKey = ocrApiKey;
        if (StringUtils.isNull(secretKey))
            secretKey = ocrSecretKey;

        RedisUtils redisUtils = SpringContextHolder.getBean("redisUtils");
        if (redisUtils.exists(ocrTokenKey))
            return StringUtils.convertString(redisUtils.get(ocrTokenKey));
        String url = "https://aip.baidubce.com/oauth/2.0/token?client_id=" + apiKey + "&client_secret="
                + secretKey + "&grant_type=client_credentials";
        try {
            String res = HttpUtil.post(url, null);
            com.alibaba.fastjson.JSONObject json = com.alibaba.fastjson.JSONObject.parseObject(res);
            log.info("百度aip去底纹验证后的access_token:{}", res);
            if (json == null || !json.containsKey("access_token"))
                return "";

            String accessToken = StringUtils.convertString(json.getString("access_token"));
            System.out.println("res:" + res);
            if (StringUtils.isNull(accessToken))
                return "";
            redisUtils.set(outOcrTokenKey, accessToken, sessionExpired);
            return accessToken;
        } catch (Exception e) {
            log.error("获取百度通用识别去底纹API token失败：" + e.getMessage(), e);
            return "";
        }
    }

    /**
     * 获取通用识别token
     * @param apiKey
     * @param secretKey
     * @return
     */
    public static String getAccessToken(String apiKey, String secretKey) {
        if (StringUtils.isNull(apiKey))
            apiKey = ocrApiKey;
        if (StringUtils.isNull(secretKey))
            secretKey = ocrSecretKey;

        RedisUtils redisUtils = SpringContextHolder.getBean("redisUtils");
        if (redisUtils.exists(ocrTokenKey))
            return StringUtils.convertString(redisUtils.get(ocrTokenKey));
        String url = "https://aip.baidubce.com/oauth/2.0/token?client_id=" + apiKey + "&client_secret="
                + secretKey + "&grant_type=client_credentials";
        try {
            String res = HttpUtil.post(url, null);
            com.alibaba.fastjson.JSONObject json = com.alibaba.fastjson.JSONObject.parseObject(res);
            log.info("百度aip验证后的access_token:{}", res);
            if (json == null || !json.containsKey("access_token"))
                return "";

            String accessToken = StringUtils.convertString(json.getString("access_token"));
            System.out.println("res:" + res);
            if (StringUtils.isNull(accessToken))
                return "";
            redisUtils.set(ocrTokenKey, accessToken, sessionExpired);
            return accessToken;
        } catch (Exception e) {
            log.error("获取百度通用识别API token失败：" + e.getMessage(), e);
            return "";
        }
    }

	/**
	 * 银行单据识别
	 *
	 * @param imgData 图片二进制
	 * @param token   调用token
	 * @return
	 */
	public static String getBankImageContent(byte[] imgData, String token) {
		// iocr 识别apiUrl
		String recogniseUrl = "https://aip.baidubce.com/rest/2.0/ocr/v1/bank_receipt_new";
		try {
			if (StringUtils.isNull(token)) {
				token = getAccessToken(ocrApiKey, ocrSecretKey);
			}
			String imgStr = Base64Util.encode(imgData);
			String imgParam = URLEncoder.encode(imgStr, "UTF-8");
			// 请求参数
			String param = "image=" + imgParam;
			if (StringUtils.isNull(token)) {
				token = getAccessToken(ocrApiKey, ocrSecretKey);
			}
			// 请求模板识别
			String result = HttpUtil.post(recogniseUrl, token, param);
			return result;
		} catch (Exception e) {
			e.printStackTrace();
			return "";
		}
	}

	/**
	 * 格式化为银行
	 *
	 * @param result
	 * @return
	 */
	public static OCRBankReturnModel convertBankReturnModel(String result) {
		if (StringUtils.isBlank(result)) {
			return null;
		}
		JSONObject bankJSON = JSONObject.parseObject(result);
		if (bankJSON == null) {
			return null;
		}
		Integer errorCode = bankJSON.getInteger("error_code");
		if (errorCode != null && errorCode.equals(0)) {
			//	解析成功,取出数据
			JSONObject data = bankJSON.getJSONObject("data");
			JSONArray ret = data.getJSONArray("ret");
			if (ret != null) {
				OCRBankReturnModel bankReturnModel = new OCRBankReturnModel();
				for (int i = 0, s = ret.size(); i < s; i++) {
					JSONObject rData = ret.getJSONObject(i);
					String wordName = rData.getString("word_name");
					String word = rData.getString("word");
					if (wordName.equals("交易日期")) {
						String day = "";
						String p1 = "yyyyMMdd";
						String p2 = "yyyy-MM-dd HH:mm:ss";
						String p3 = "yyyy-MM-ddHH:mm:ss";
						String p4 = "yyyy年MM月dd日";
						word = word.replaceAll("：", ":");
						List<String> patternList = new ArrayList<>();
						patternList.add(p1);
						patternList.add(p2);
						patternList.add(p3);
						patternList.add(p4);
						for (String pattern : patternList) {
							Boolean vd = StringUtils.validatorDate(word, pattern);
							if (vd) {
								//	格式化日期
								Date date = DateUtil.convertDate(word, pattern);
								day = DateUtil.convertString(date);
								break;
							}
						}
						bankReturnModel.setPayTime(day);
					}
					if (wordName.equals("付款金额")) {
						//	格式化金额
						Double money = StringUtils.tranMoney(word);
						bankReturnModel.setMoney(money);
					}
					if (wordName.equals("付款账户")) {
						bankReturnModel.setPayOrigin(word);
					}
				}
				return bankReturnModel;
			}
		}
		return null;
	}
}
